<?php

namespace app\http;

use think\facade\Cache;
use think\worker\Server;
use utils\LogUtils;
use Workerman\Lib\Timer;


class Worker extends Server
{

    protected $socket = 'websocket://0.0.0.0:2347';
    //进程数量  window 下不管用
    //protected $option = ['count' => 4];


    protected $option = ['transport' => 'ssl', 'count' => 4];
    protected $context = [
        'ssl' => [
            //'local_cert' => 'C:\phpstudy_pro\zs\test.kyd5.cn_bundle.pem',
            //'local_pk' => 'C:\phpstudy_pro\zs\test.kyd5.cn.key',
            //本地测试
            //'local_cert'=>'D:\phpstudy_pro\WWW\take-num\zs\local_pem.pem',
            //'local_pk'=>'D:\phpstudy_pro\WWW\take-num\zs\local_key.key',
            'verify_peer' => false,
            'verify_peer_name' => false,
            'allow_self_signed' => true,
        ],
    ];

    public $conn_list01 = [];
    public $conn_list02 = [];
    public $startTimeList = [];
    public $requestStartList = [];
    public $conn_time = [];
    public $no_send = [];
    public $no_send_print = [];
    public $no_send_chat = [];


    public function __construct()
    {
        $this->context['ssl']['local_cert'] = getFileROOT() . '\zs\ws.kyd5.cn_bundle.pem';
        $this->context['ssl']['local_pk'] = getFileROOT() . '\zs\ws.kyd5.cn.key';

        parent::__construct();
    }

    protected function init()
    {
        parent::init();
    }

    public function onWorkerStart()
    {
        //定时任务
        Timer::add(2, function () {

            //叫号数据
            $num_data_array = Cache::get('num_data', []);
            Cache::set('num_data', []);

            //交换数据
            $no_send = $this->no_send;
            $this->no_send = [];

            //$this->exTask($no_send);

            //$this->exTask($num_data_array);

            $this->exTask_data($no_send, 2);
            $this->exTask_data($num_data_array, 2);

            //打印数据
            $print_data_array = Cache::get('print_data', []);
            Cache::set('print_data', []);
            $no_send_print = $this->no_send_print;
            $this->no_send_print = [];

            $this->exTask_data($no_send_print, 0);
            $this->exTask_data($print_data_array, 0);

            //聊天数据
            $chat_data_array = Cache::get('chat_data', []);
            Cache::set('chat_data', []);
            //$no_send_chat = $this->no_send_chat;
            //$this->no_send_chat = [];

            //$this->exTask_data_chat($no_send_chat, 1);
            $this->exTask_data_chat($chat_data_array, 1);

        });
    }


    /**
     * @param $array
     */
    private function exTask_data($array, $type)
    {
        while ($array && is_array($array) && count($array) > 0) {
            $result = array_shift($array);

            $data = $result['data'];

            //var_dump($data);

            if (!$data) {
                LogUtils::log('data为空=type=' . $type);
                return;
            }


            $Device_ID = $data['From'];

            $su = json_encode($data, JSON_UNESCAPED_UNICODE);
            if ($type == 0) {
                //打印
                if (!isset($data['Websocket'])) {
                    LogUtils::log('data中 Websocket为空');
                    return;
                }
                $Websocket = $data['Websocket'];
            } else if ($type == 1) {


            } else if ($type == 2) {
                $r = $data;
                //LogUtils::log($r);
                //$r['Code'] = 100;
                //$r['Call_Type'] = 'notify|请|@|号到|#|号窗口办理|';
                //$r['Sound_Type'] = 0;

                $r['call_no'] = $r['Call_NO'];
                $r['Win_ID'] = intval($r['Win_ID']);
                //$r['Win_ID'] = $r['Win_ID'];
                $su = json_encode($r, JSON_UNESCAPED_UNICODE);
            }


            //LogUtils::error("打印逻辑=".$su);
            //设备是否连接
            if ($this->isDeviceConn02($Device_ID, $Websocket)) {
                //心跳时间太长了认为设备断开了
                /*if (time() - $this->conn_time[$Device_ID] > 10) {

                    array_push($this->no_send_print, $result);
                    LogUtils::log("时间大于10s,放入集合 Device_ID".$Device_ID);
                    $this->closeDeviceConn($Device_ID);
                } else {
                    $this->setMessage2AllDevice(0, $Device_ID, $su);
                }*/

                $this->setMessage2AllDevice02(0, $Device_ID, $Websocket, $su);

            } else {

                //LogUtils::log("没有设备连接,放入集合 Device_ID=" . $Device_ID . ", Websocket=" . $Websocket . ", type=" . $type);

                if ($type == 0) {
                    array_push($this->no_send_print, $result);
                } else if ($type == 2) {
                    array_push($this->no_send, $result);
                }
            }
            //重新赋值 再次写入 Cache
        }

    }

    private function exTask_data_chat($array, $type)
    {
        while ($array && is_array($array) && count($array) > 0) {
            $result = array_shift($array);

            $data = $result['data'];

            //var_dump($data);

            if (!$data) {
                LogUtils::log('data为空=type=' . $type);
                return;
            }

            $Device_ID = $data['From'];
            $su = json_encode($data, JSON_UNESCAPED_UNICODE);

            if (!isset($data['member'])) {
                LogUtils::log('data中 member 为空');
                return;
            }
            if (!isset($data['memberid'])) {
                LogUtils::log('data中 memberid 为空');
                return;
            }
            $member = $data['member'];
            $memberid = $data['memberid'];

            //客服是否在线
            $kf_is_conn = $this->isDeviceConn02($Device_ID, $Device_ID);
            //要接收消息的对方是否在线
            $member_is_conn = $this->isDeviceConn02($Device_ID, $member);
            $memberId_is_conn = $this->isDeviceConn02($Device_ID, $memberid);

            //并且接受消息的对象不是客服, 如果接受消息的对象是客服, 在 代码注释999 处会发
            $isNotKf = $Device_ID != $member && $Device_ID != $memberid;

            // From/Device_ID  和 Websocket 是一样的值, 是客服, 客服和接收者都在, 会给客服发一份消息
            /*if ($kf_is_conn && ($member_is_conn || $memberId_is_conn) && $isNotKf) {
                $this->setMessage2AllDevice02(0, $Device_ID, $Device_ID, $su);
            }*/

            //设备是否连接
            if ($member_is_conn) {
                $this->setMessage2AllDevice02(0, $Device_ID, $member, $su);
            }

            if ($memberId_is_conn && $member != $memberid) {
                $this->setMessage2AllDevice02(0, $Device_ID, $memberid, $su);
            }

            if ($kf_is_conn && $isNotKf) {
                $this->setMessage2AllDevice02(0, $Device_ID, $Device_ID, $su);
            }

            /*if ($member_is_conn  || $memberId_is_conn) {

                if ($member == $memberid){
                    //999
                    $this->setMessage2AllDevice02(0, $Device_ID, $member, $su);
                }else{
                    //999
                    $this->setMessage2AllDevice02(0, $Device_ID, $member, $su);
                    $this->setMessage2AllDevice02(0, $Device_ID, $memberid, $su);
                }
            } else {

                //LogUtils::log("没有设备连接,放入集合 Device_ID=" . $Device_ID . ", member=" . $member . ", memberid=" . $memberid);

                if ($type == 1) {
                    array_push($this->no_send_chat, $result);
                }
            }*/


        }

    }

    public function onMessage($connection, $d)
    {
        //LogUtils::error("444");
        //Cache::set('5555',);
        LogUtils::log($d);
        if (empty($d)) {
            $su = $this->fail02(403, '接受到的数据为空');
            $connection->send($su);
            return;
        }

        $data = json_decode($d);
        if (!isset($data->From)) {
            //$this->setErrorMessage($connection, 'Device_ID 空,接受到的信息=' . $d);
            $su = $this->fail02(404, 'From 空,接受到的信息=' . $d);
            $connection->send($su);
            return;
        }
        $From = 0;
        $Device_ID = isset($data->Device_ID) ? $data->Device_ID : "";
        $Websocket = strval(isset($data->Websocket) ? $data->Websocket : "");
        //来自于客户端
        if (empty($Device_ID) || $Device_ID == 0 || $Device_ID == '0') {
            $From = 1;
            $Device_ID = strval($data->From);
        }
        //来自机器端
        if ($data->From == 0 || $data->From == '0') {
            if (!isset($data->Device_ID)) {
                $su = $this->fail02(404, 'Device_ID 空,接受到的信息=' . $d);
                $connection->send($su);
                return;
            }
            $From = 0;
            $Device_ID = strval($data->Device_ID);
        }

        //记录连接时间
        $this->conn_time[$Device_ID] = time();

        switch (intval($data->Code)) {
            case 0:
                if ($From == 1) {

                    $this->clearMyListAndConnId($this->conn_list01, $Device_ID);

                    $this->conn_list01[$Device_ID] = $connection->id;
                    $connection->send($this->ok2('接受 $From:' . $Device_ID));
                } else {
                    // $this->conn_list02 = array_merge($this->conn_list02, [$Device_ID => $connection->id]);
                    $key = $Device_ID . '@@@@' . $Websocket;

                    $this->clearMyListAndConnId($this->conn_list02, $key);

                    $this->conn_list02[$key] = $connection->id;

                    $connection->send($this->ok2('接受 $Device_ID:' . $Device_ID));
                }
                break;
            case 10:
                //客户端心跳包(打印的会发送)
                // 获取当前时间
                $current_time = date('Y-m-d H:i:s');
                $su = $this->ok3(10, $current_time);
                $connection->send($su);

                break;
            case 999:
                //$a = 3/0;
                break;
            default:
                if ($From == 1) {
                    //来自前端
                    if (empty($this->conn_list02[$Device_ID . '@@@@0'])) {
                        $this->setErrorMessage($connection, '通过设备号未找到 设备');
                        return;
                    }
                    //$this->getConn(2, $Device_ID)->send($d);
                    $this->setMessage2AllDevice(0, $Device_ID, $d);
                    $connection->send($this->ok2('成功'));
                } else {
                    if (empty($this->conn_list01[$Device_ID])) {
                        $this->setErrorMessage($connection, '通过设备号未找到 前端设备');
                        return;
                    }
                    $this->getConn(1, $Device_ID)->send($d);
                    $connection->send($this->ok2('成功'));
                }
                break;
        }

    }


    public function ok($Data)
    {
        $su = ['Code' => 200, 'Data' => $Data, 'message' => 'success'];
        $su = json_encode($su, JSON_UNESCAPED_UNICODE);
        return $su;
    }

    public function ok2($Message)
    {
        $su = ['Code' => 200, 'Data' => null, 'message' => $Message];
        $su = json_encode($su, JSON_UNESCAPED_UNICODE);
        return $su;
    }

    public function ok3($Code, $Data)
    {
        $su = ['Code' => $Code, 'Data' => $Data, 'message' => null];
        $su = json_encode($su, JSON_UNESCAPED_UNICODE);
        return $su;
    }

    public function fail($Message)
    {
        $su = ['Code' => 400, 'Data' => null, 'message' => $Message];
        $su = json_encode($su, JSON_UNESCAPED_UNICODE);
        return $su;
    }

    public function fail02($Code, $Message)
    {
        $su = ['Code' => $Code, 'Data' => null, 'message' => $Message];
        $su = json_encode($su, JSON_UNESCAPED_UNICODE);
        return $su;
    }

    /**
     * @param $connection
     * @return false|string
     */
    public function setErrorMessage($connection, $hint)
    {
        $connection->send($this->fail($hint));
    }

    /**
     * 当连接建立时触发的回调函数
     * @param $connection
     */
    public function onConnect($connection)
    {
        $connection->send($this->ok2('success,id=' . $connection->id));
    }

    /**
     * 当连接断开时触发的回调函数
     * @param $connection
     */
    public function onClose($connection)
    {
        foreach ($this->conn_list01 as $key => $value) {
            if ($connection->id == $value) {
                LogUtils::error('close conn_list01=' . $key . '==' . $value);
                unset($this->conn_list01[$key]);
                break;
            }
        }
        foreach ($this->conn_list02 as $key => $value) {
            if ($connection->id == $value) {
                LogUtils::error('close conn_list02=' . $key . '==' . $value);
                unset($this->conn_list02[$key]);
                break;
            }
        }
        LogUtils::log("onClose");
        $this->clear($connection);


    }

    /**
     * 当客户端的连接上发生错误时触发
     * @param $connection
     * @param $code
     * @param $msg
     */
    public function onError($connection, $code, $msg)
    {
        LogUtils::error('worker onError:' . $code . '=' . $msg);
    }


    /**
     * @param $from
     * @param $key  不一定一定是 $Device_ID
     * @return mixed|null
     */
    protected function getConn($from, $key)
    {

        if ($from == 1) {
            $id = $this->conn_list01[$key];
        } else {
            $id = $this->conn_list02[$key];
        }

        if ($this->worker->connections[$id]) {
            $conn = $this->worker->connections[$id];
            return $conn;
        }

        //LogUtils::error('找到');
        return null;
    }


    protected function setMessage2AllDevice($from, $Device_ID, $d)
    {
        $isSend = false;
        if ($from == 1) {

        } else {
            foreach ($this->conn_list02 as $key => $value) {
                // $key = 999@@@@0 , 999@@@@1
                $array = explode('@@@@', $key);

                if ($array[0] == $Device_ID) {
                    //池子里面连接存在
                    if (isset($this->worker->connections[$value])) {
                        $conn = $this->worker->connections[$value];
                        $conn->send($d);
                        $isSend = true;
                    }
                }
            }
        }
        return $isSend;
    }

    protected function setMessage2AllDevice02($from, $Device_ID, $Websocket, $d)
    {
        $isSend = false;
        if ($from == 1) {

        } else {
            foreach ($this->conn_list02 as $key => $value) {
                // $key = 999@@@@0 , 999@@@@1
                //$array = explode('@@@@', $key);
                $str = $Device_ID . '@@@@' . $Websocket;

                if ($key == $str) {
                    //池子里面连接存在
                    if (isset($this->worker->connections[$value])) {
                        $conn = $this->worker->connections[$value];
                        $conn->send($d);
                        $isSend = true;
                    }
                }
            }
        }
        return $isSend;
    }

    protected function isDeviceConn($Device_ID)
    {
        foreach ($this->conn_list02 as $key => $value) {
            // $key = 999@@@@0 , 999@@@@1
            $array = explode('@@@@', $key);

            if ($array[0] == $Device_ID) {
                //池子里面连接存在
                if (isset($this->worker->connections[$value])) {
                    return true;
                }
            }
        }
        return false;
    }

    protected function isDeviceConn02($Device_ID, $Websocket)
    {
        foreach ($this->conn_list02 as $key => $value) {
            // $key = 999@@@@0 , 999@@@@1
            $str = $Device_ID . '@@@@' . $Websocket;

            if ($key == $str) {
                //池子里面连接存在
                if (isset($this->worker->connections[$value])) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * @param $connection
     */
    private function clear($connection)
    {
        if (isset($connection->id)) {
            // 连接断开时删除映射
            unset($this->worker->connections[$connection->id]);
        }
    }

    private function clearMyListAndConnId($array, $key)
    {
        if (isset($array[$key])) {
            $id = $array[$key];

            //可能已经提前断开了, 要判断一下
            if (isset($this->worker->connections[$id])) {
                $this->worker->connections[$id]->close();
            }

            //$this->onClose($this->worker->connections[$id]);
            unset($array[$key]);
        }
    }


    /**
     * 断开连接
     * @param $Device_ID
     */
    protected function closeDeviceConn($Device_ID)
    {

        foreach ($this->conn_list02 as $key => $value) {
            // $key = 999@@@@0 , 999@@@@1
            $array = explode('@@@@', $key);

            if ($array[0] == $Device_ID) {
                //池子里面连接存在
                if (isset($this->worker->connections[$value])) {
                    $this->worker->connections[$value]->close();
                }
            }
        }
    }

    /**
     * @param $array
     */
//    private function exTask($array)
//    {
//        while ($array && is_array($array) && count($array) > 0) {
//            $result = array_shift($array);
//
//            //var_dump($result);
//
//            $data = $result['data'];
//            //var_dump($data);
//            if (!$data) {
//                LogUtils::log('叫号 data为空');
//                return;
//            }
//
//            $Device_ID = $data['From'];
//            $Websocket = $data['Websocket'];
//            if (!$Device_ID) {
//                LogUtils::log('叫号 $Device_ID为空');
//                return;
//            }
//
//            $r = $data;
//            //LogUtils::log($r);
//            //$r['Code'] = 100;
//            //$r['Call_Type'] = 'notify|请|@|号到|#|号窗口办理|';
//            //$r['Sound_Type'] = 0;
//
//            $r['call_no'] = $r['Call_NO'];
//            $r['Win_ID'] = intval($r['Win_ID']);
//            //$r['Win_ID'] = $r['Win_ID'];
//            $su = json_encode($r, JSON_UNESCAPED_UNICODE);
//
//
//            //设备是否连接
//
//            if ($this->isDeviceConn02($Device_ID, $Websocket)) {
//                //心跳时间太长了认为设备断开了
//                /*if (time() - $this->conn_time[$Device_ID] > 10) {
//
//                    array_push($this->no_send, $result);
//                    LogUtils::log("时间大于10s,放入集合 Device_ID".$Device_ID);
//                    $this->closeDeviceConn($Device_ID);
//                } else {
//                    $this->setMessage2AllDevice(0, $Device_ID, $su);
//                }*/
//                $this->setMessage2AllDevice02(0, $Device_ID, $Websocket, $su);
//            } else {
//
//                LogUtils::log("没有设备连接,放入集合 Device_ID=" . $Device_ID);
//                array_push($this->no_send, $result);
//            }
//            //重新赋值 再次写入 Cache
//        }
//
//    }
}